package aircraft;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 游戏世界
 */
public class World extends JPanel {
    public static final int WIDTH = 400;
    public static final int HEIGHT = 700;

    public static final int START = 0;
    public static final int RUNNING = 1;
    public static final int PAUSE = 2;
    public static final int GAME_OVER = 3;
    private int state = START;

    private Sky sky = new Sky();
    private Hero hero = new Hero();
    private FlyingObject[] enemies = {};
    private Bullet[] bullets = {};
    private AirBullet[] airBullets = {};

    private int score = 0;

    private FlyingObject nextFlyingObject() {
        Random random = new Random();
        int type = random.nextInt(20);
        if (type < 5) {
            return new Bee();
        } else if (type < 13) {
            return new Airplane();
        } else {
            return new BigAirplane();
        }
    }

    private int enterIndex = 0;

    private void enterAction() {
        enterIndex++;
        if (enterIndex % 40 == 0) {
            FlyingObject obj = nextFlyingObject();
            enemies = Arrays.copyOf(enemies, enemies.length + 1);
            enemies[enemies.length - 1] = obj;
        }
    }

    private int shootIndex = 0;

    private void bulletsAction() {
        shootIndex++;
        if (shootIndex % 30 == 0) {
            Bullet[] bs = hero.shoot();
            bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
            System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length);
        }
    }

    /**
     * 扩展功能
     */
    private int airShootIndex = 0;

    private void airBulletsAction() {
        airShootIndex++;
        if (airShootIndex % 100 == 0) {
            for (int i = 0; i < enemies.length; i++) {
                FlyingObject fo = enemies[i];
                if (fo instanceof BigAirplane) {
                    BigAirplane ba = (BigAirplane) enemies[i];
                    AirBullet ab = ba.airShoot();
                    airBullets = Arrays.copyOf(airBullets, airBullets.length + 1);
                    airBullets[airBullets.length - 1] = ab;
                }
            }
        }
    }

    private void stepAction() {
        sky.step();
        for (int i = 0; i < enemies.length; i++) {
            enemies[i].step();
        }
        for (int i = 0; i < bullets.length; i++) {
            bullets[i].step();
        }
        for (int i = 0; i < airBullets.length; i++) {
            airBullets[i].step();
        }
    }

    private void outOfBoundsAction() {
        for (int i = 0; i < enemies.length; i++) {
            if (enemies[i].isOutOfBounds() || enemies[i].isRemove()) {
                enemies[i] = enemies[enemies.length - 1];
                enemies = Arrays.copyOf(enemies, enemies.length - 1);
            }
        }
        for (int i = 0; i < bullets.length; i++) {
            if (bullets[i].isOutOfBounds() || bullets[i].isRemove()) {
                bullets[i] = bullets[bullets.length - 1];
                bullets = Arrays.copyOf(bullets, bullets.length - 1);
            }
        }
    }

    private void bulletBangAction() {
        for (int i = 0; i < bullets.length; i++) {
            Bullet b = bullets[i];
            for (int j = 0; j < enemies.length; j++) {
                FlyingObject f = enemies[j];
                if (b.isLive() && f.isLive() && f.isHit(b)) {
                    b.goDead();
                    f.goDead();
                    if (f instanceof EnemyScore) {
                        EnemyScore es = (EnemyScore) f;
                        score += es.getScore();
                    }
                    if (f instanceof EnemyAward) {
                        EnemyAward ea = (EnemyAward) f;
                        int type = ea.getAwardType();
                        switch (type) {
                            case EnemyAward.FIRE:
                                hero.addFire();
                                break;
                            case EnemyAward.LIFE:
                                hero.addLife();
                                break;
                        }
                    }
                }
            }
        }
    }

    private void heroBangAction() {
        for (int i = 0; i < enemies.length; i++) {
            FlyingObject fo = enemies[i];
            if (fo.isLive() && hero.isLive() && fo.isHit(hero)) {
                fo.goDead();
                hero.subtractLife();
                hero.clearFire();
            }
        }
    }

    private void checkGameOverAction() {
        if (hero.getLife() <= 0) {
            state = GAME_OVER;
        }
    }

    /**
     * 扩展功能
     */
    private void airBulletBangAction() {
        for (int i = 0; i < airBullets.length; i++) {
            AirBullet ab = airBullets[i];
            if (ab.isLive() && hero.isLive() && ab.isHit(hero)) {
                ab.goDead();
                hero.subtractLife();
                hero.clearFire();
            }
        }
    }

    private void action() {
        MouseAdapter m = new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                if (state == RUNNING) {
                    int x = e.getX();
                    int y = e.getY();
                    hero.stepTo(x, y);
                }
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                switch (state) {
                    case START:
                        state = RUNNING;
                        break;
                    case GAME_OVER:
                        score = 0;
                        sky = new Sky();
                        hero = new Hero();
                        enemies = new FlyingObject[0];
                        bullets = new Bullet[0];
                        airBullets = new AirBullet[0];
                        state = START;
                        break;
                }
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if (state == PAUSE) {
                    state = RUNNING;
                }
            }

            @Override
            public void mouseExited(MouseEvent e) {
                if (state == RUNNING) {
                    state = PAUSE;
                }
            }
        };

        this.addMouseListener(m);
        this.addMouseMotionListener(m);
        Timer timer = new Timer();
        int interval = 10;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (state == RUNNING) {
                    enterAction();
                    bulletsAction();
                    airBulletsAction();
                    stepAction();
                    bulletBangAction();
                    airBulletBangAction();
                    heroBangAction();
                    outOfBoundsAction();
                    checkGameOverAction();
                }
                repaint();
            }
        }, interval, interval);
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(sky.getImage(), sky.x, sky.y, null);
        g.drawImage(sky.getImage(), sky.x, sky.getY1(), null);
        g.drawImage(hero.getImage(), hero.x, hero.y, null);
        for (int i = 0; i < enemies.length; i++) {
            FlyingObject f = enemies[i];
            g.drawImage(f.getImage(), f.x, f.y, null);
        }
        for (int i = 0; i < bullets.length; i++) {
            Bullet b = bullets[i];
            g.drawImage(b.getImage(), b.x, b.y, null);
        }
        for (int i = 0; i < airBullets.length; i++) {
            AirBullet ab = airBullets[i];
            g.drawImage(ab.getImage(), ab.x, ab.y, null);
        }
        g.drawString("SCORE: " + score, 10, 25);
        g.drawString("LIFE: " + hero.getLife(), 10, 45);

        switch (state) {
            case START:
                g.drawImage(Images.start, 0, 0, null);
                break;
            case PAUSE:
                g.drawImage(Images.pause, 0, 0, null);
                break;
            case GAME_OVER:
                g.drawImage(Images.gameover, 0, 0, null);
                break;
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH + 16, HEIGHT + 39);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true); // 设置窗口可见
        frame.setResizable(false); // 设置窗口能否改变

        world.action();
    }
}
